
#include "EpollPoller.h"
#include "Channel.h"
#include "Logger.h"

#include <errno.h>
#include <string.h>
#include <unistd.h>

const int kNew = -1;
const int kAdded = 1;
const int kDeleted = 2;

EpollPoller::EpollPoller(EventLoop *loop) : Poller(loop), epollfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListSizze)
{
    if (epollfd_ < 0)
    {
        LOG_FATAL("epoll create error, %d", errno);
    }
};

EpollPoller::~EpollPoller()
{
    ::close(epollfd_);
};

Timestamp EpollPoller::poll(int timeout, ChannelList *activateChannels)
{
    Timestamp now = Timestamp::now();
    // wait
    // 将发生的事件回填到 events_
    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeout);
    if (numEvents > 0)
    {
        fillActiveChannels(numEvents, activateChannels);
        // 加上扩容
        if (numEvents == events_.size())
        {
            events_.resize(events_.size() * 2);
        }
        
    }
    else if (numEvents == 0)
    {
        LOG_INFO("not happent !");
    }
    else
    {
        LOG_ERROR("error : %d", errno);
    }

    return now;
};

void EpollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{
    // 
    LOG_INFO("fillActiveChannels numEvents = %d", numEvents);
    for (size_t i = 0; i < numEvents; i++)
    {
        Channel *channel = static_cast<Channel *>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);
    }
    
}

void EpollPoller::updateChannel(Channel *channel)
{
    // 如果当前是new 或 del。证明是新增，new应该保存fd到channels_
    // else 就是已经有了， 如果没有事件则是删除，否则是mod
    const int index = channel->index();
    LOG_INFO("updateChannel start.. fd=%d, events=%d, index=%d \n", channel->fd(), channel->events(), channel->index());
    if (index == kNew || index == kDeleted)
    {
        if (index == kNew)
        {
            channels_[channel->fd()] = channel;
        }
        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else
    {
        if (channel->isNonoEvent())
        {
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
};
void EpollPoller::removeChannel(Channel *channel)
{
    channels_.erase(channel->fd());
    if (channel->index() == kAdded)
    {
        update(EPOLL_CTL_DEL, channel);
    }
    else
    {
        LOG_INFO("removeChannel start , and index = %d", channel->index());
    }
    channel->set_index(kNew);
};

void EpollPoller::update(int opearete, Channel *channel)
{
    // 其实就是调用 epoll_ctl
    epoll_event event;
    memset(&event, 0, sizeof(event));
    

    event.events = channel->events();
    // ptr可以放自定义的东西，在这里和fd做kv绑定
    event.data.fd = channel->fd();
    event.data.ptr = channel;

    LOG_INFO("epoll_ctl op=%d, fd=%d, events=%d", opearete, channel->fd(), event.events);

    if (::epoll_ctl(epollfd_, opearete, channel->fd(), &event) < 0)
    {
        // 如果是del error， 别的应该是fatal
        if (opearete == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctr error, %d", errno);
        }
        else
        {
            LOG_FATAL("epoll_ctr error, %d", errno);
        }
    }
}